#include "timer.hpp"

namespace libco {

Timer::Timer(uint64_t ms, bool recurring, basefunc cb, TimerManager* timermgr)
: m_ms(ms), m_recurring(recurring), m_cb(cb), m_manager(timermgr)
{
    m_next = GetElapsedMs() + ms;
}

Timer::Timer(uint64_t next)
: m_next(next) 
{

}

bool Timer::cmp::operator()(const Timer::ptr& l, const Timer::ptr& r) const {
    return l->m_next < r->m_next;
}

Timer::ptr TimerManager::addTimer(uint64_t ms, basefunc cb, bool recurring) {
    RWMutex::WriteLock lock(m_rwmutex);
    Timer::ptr t(new Timer(ms, recurring, cb, this));
    addTimer(t, lock);
    return t;
}

void TimerManager::addTimer(Timer::ptr t, RWMutex::WriteLock& wlock) {
    m_timers.insert(t);
    wlock.unlock();
}

void TimerManager::listAllExpired(std::vector<basefunc>& expired_cb_vec) {
    uint64_t now_ms = GetElapsedMs();
    {
        RWMutex::ReadLock rlock(m_rwmutex);
        if(m_timers.empty()) {
            return;
        }
        if((*m_timers.begin())->m_next > now_ms) {
            return;
        }
    }
    RWMutex::WriteLock lock(m_rwmutex);

    std::vector<Timer::ptr> expired_timer_vec;
    Timer::ptr now_timer(new Timer(now_ms));
    auto iter = m_timers.lower_bound(now_timer);
    while(iter != m_timers.end() && (*iter)->m_next == now_ms) {
        ++iter;
    }
    expired_timer_vec.insert(expired_timer_vec.begin(), m_timers.begin(), iter);
    m_timers.erase(m_timers.begin(), iter);
    for(auto& timer : expired_timer_vec) {
        expired_cb_vec.push_back(timer->m_cb);
        if (timer->m_recurring) {
            timer->m_next = timer->m_ms + now_ms;
        }
    }
    return ;
}

uint64_t TimerManager::getNextTimerMs() {
    RWMutex::ReadLock lock(m_rwmutex);
    if(m_timers.empty()) {
        return ~0ull;
    }
    uint64_t next_ms = (*m_timers.begin())->m_next;
    if(next_ms <= GetCurrentTimeMs()) {
        return 0;
    } else {
        return (*m_timers.begin())->m_next - GetCurrentTimeMs();
    }

} 

} // namespace libco